#include common_scripts\utility;
#include maps\mp\_utility;
#include maps\mp\gametypes\_hud_util;
#include z_mod\_utility;
#using_animtree("multiplayer");


init()
{
    SetupAnims();
    
    level.zzz1 = loadFx("muzzleflashes/mp16_flash_view");
    level.zzz2 = loadFx("muzzleflashes/m16_flash_wv");
    
    level waittill("z_run_threads");
    
    level thread AI_Spawner();
    level thread MasterBot_Spawner();
}

AI_Damage()
{
    last_attacker = undefined;
    
    while(self.hp > 0) {
        self.box waittill("damage", damage, attacker, direction_vec, point, type, modelName, tagName, partName, iDFlags, sWeapon);
        
        last_attacker = attacker;
        
        // +50% урона от тяжелых снайперских винтовок
        if(sWeapon == "cheytac_mp" || sWeapon == "barrett_mp") {
            damage *= 1.5;
        }
        
        // flash_grenade_mp, concussion_grenade_mp
        if(sWeapon == "flash_grenade_mp" || type == "MOD_GRENADE_SPLASH") {
            //self thread AI_Shellshock();
        }
        
        self.hp -= damage;
    }
    
    self AI_Death();
}

AI_Death()
{
    self notify("z_death");
    
    if(self.isCrouching)
        self thread AI_DeathProcess(level.zAI_Anims["death_crouch"], 30);
    else
        self thread AI_DeathProcess(level.zAI_Anims["death_stand"], 30);
    
    wait(0.05);
    
    self.weapon delete();
    self.head delete();
    self delete();
}

AI_DeathProcess(death_anim, duration)
{
    self.box delete();
    
    death_body = spawn("script_model", self.origin);
    death_body setModel(self.death[0]);
    
    death_body.head = spawn("script_model", death_body getTagOrigin("j_spine4"));
    death_body.head.angles = (270, 0, 270);
    death_body.head setModel(self.death[1]);
    death_body.head linkTo(death_body, "j_spine4");
    
    /*death_body.weapon = spawn("script_model", death_body getTagOrigin("tag_weapon_right"));
    death_body.weapon setModel(getWeaponModel(self.weapon.name, self.weapon.camo));
    death_body.weapon z_WeaponModelManageTags(self.weapon.name);
    death_body.weapon linkTo(death_body, "tag_weapon_right");*/
    
    death_body rotateTo(self.angles, 0.025);
    
    self.weapon hide();
    self.head hide();
    self hide();
    
    death_body scriptModelPlayAnim(death_anim);
    death_body.head scriptModelPlayAnim(death_anim);
    
    wait(duration);
    
    //death_body.weapon delete();
    death_body.head delete();
    death_body delete();
}

AI_Reload()
{
    self endon("z_death");
    
    self.isReloading = true;
    
    wait(5.0);
    self.weapon.clip_cur = self.weapon.clip_max;
    
    self.isReloading = false;
}

AI_Shoot(target_origin)
{
    start = (0, 0, 0);
    end = (0, 0, 0);
    height = (0, 0, 0);
    
    forward = anglesToForward(self.angles);
    forward = (forward[0], forward[1], 0);
    forward = vectorNormalize(forward);
    
    if(self.isCrouching) {
        height = (0, 0, 0); // ???
    } else {
        height = (0, 0, 50);
    }
    
    start = self.origin + height + vector_Multiply(forward, 25);
    
    if(isDefined(target_origin))
        end = target_origin;
    else
        end = self.origin + height + vector_Multiply(forward, 55);
    
    magicBullet(self.weapon.name, start, end, level.zMasterBot);
    playFxOnTag(level.zzz1, self.weapon, "tag_flash");
}

AI_Shooting()
{
    self endon("z_death");
    
    delay = weaponFireTime(self.weapon.name) * 1.15;
    
    while(1) {
        if(!isDefined(self.activeTarget))
            self waittill("z_target", target);
        
        if(!self.isShooting) {
            if(self.isCrouching) {
                self scriptModelPlayAnim(level.zAI_Anims["ads_crouch"]);
                self.head scriptModelPlayAnim(level.zAI_Anims["ads_crouch"]);
            } else {
                self scriptModelPlayAnim(level.zAI_Anims["ads_stand"]);
                self.head scriptModelPlayAnim(level.zAI_Anims["ads_stand"]);
            }
        }
        
        while(isDefined(self.activeTarget) && self.weapon.clip_cur > 0/* && bulletTracePassed(self.head getTagOrigin("tag_eye"), self.activeTarget getTagOrigin("j_spine4"), true, self.box)*/) {
            angles_to_enemy = vectorToAngles(self.activeTarget.origin - self.origin);
            
            self rotateTo((0, angles_to_enemy[1], 0), 0.1);
            self.isShooting = true;
            
            self AI_Shoot(self.activeTarget getTagOrigin("j_spine4") + (randomIntRange(-50, 50), randomIntRange(-50, 50), randomIntRange(-20, 20)));
            self.weapon.clip_cur--;
            
            wait(delay);
        }
        
        if(isDefined(self.activeTarget) && !self.weapon.clip_cur) {
            self AI_Reload();
        }
        
        if(!isDefined(self.activeTarget) && self.isShooting) {
            self.isShooting = false;
            
            if(self.isCrouching) {
                self scriptModelPlayAnim(level.zAI_Anims["idle_crouch"]);
                self.head scriptModelPlayAnim(level.zAI_Anims["idle_crouch"]);
            } else {
                self scriptModelPlayAnim(level.zAI_Anims["idle_stand"]);
                self.head scriptModelPlayAnim(level.zAI_Anims["idle_stand"]);
            }
        }
    }
}

AI_Spawner()
{
    level.zUnit = undefined;
    
    while(1) {
        level waittill("something");
        
        if(isDefined(level.zUnit)) {
            //level.zUnit rotateTo((0, randomIntRange(-180, 180), 0), 1);
            
            //level.zUnit AI_Shoot();
            //level.zMasterBot sayAll(weaponFireTime(level.zUnit.weapon.name));
            
            continue;
        }
        
        level.zUnit = AI_SpawnUnit((-1370, 5340, 2776), (0, -180, 0), "m4_eotech_gl_mp", undefined, 100, 0.5);
    }
}

AI_SpawnUnit(spawn_origin, spawn_angles, primary_weapon, secondary_weapon, health, skill)
{
    unit = spawn("script_model", spawn_origin);
    unit setModel("mp_body_us_army_assault_a");
    
    unit.head = spawn("script_model", unit getTagOrigin("j_spine4"));
    unit.head.angles = (270, 0, 270);
    unit.head setModel("head_us_army_a");
    unit.head linkTo(unit, "j_spine4", (0, 0, 0), (0, 0, 0));
    
    unit.weapon = spawn("script_model", unit getTagOrigin("tag_weapon_right"));
    unit.weapon.name = primary_weapon;
    unit.weapon.camo = 0;
    unit.weapon.clip_cur = weaponClipSize(primary_weapon);
    unit.weapon.clip_max = unit.weapon.clip_cur;
    unit.weapon setModel(getWeaponModel(unit.weapon.name, unit.weapon.camo));
    unit.weapon z_WeaponModelManageTags(unit.weapon.name);
    unit.weapon linkTo(unit, "tag_weapon_right", (0, 0, 0), (0, 0, 0));
    
    unit.box = spawn("script_model", unit getTagOrigin("j_spinelower") + (-5, 0, -5));
    unit.box setModel("com_plasticcase_beige_big");
    unit.box cloneBrushmodelToScriptmodel(level.airDropCrateCollision);
    unit.box.angles = (90, 0, 0);
    unit.box hide();
    unit.box setCanDamage(true);
    unit.box.health = 99999;
    unit.box.maxhealth = 99999;
    unit.box linkTo(unit, "j_spinelower", (0, 0, 0), (0, 0, 0));
    
    unit.death = [];
    unit.death[0] = "mp_body_us_army_assault_a";
    unit.death[1] = "head_us_army_a";
    
    unit.hp = health;
    unit.skill = skill;
    unit.type = "grenadier";
    
    unit.isAlarming = false;
    unit.isBeingFlashed = false;
    unit.isCrouching = false;
    unit.isMoving = false;
    unit.isReloading = false;
    unit.isShooting = false;
    
    unit.activeTarget = undefined;
    unit.lastTarget = undefined;
    
    unit scriptModelPlayAnim(level.zAI_Anims["idle_stand"]);
    unit.head scriptModelPlayAnim(level.zAI_Anims["idle_stand"]);
    
    unit rotateTo(spawn_angles, 0.1);
    
    unit thread AI_Damage();
    unit thread AI_TargetSelector();
    unit thread AI_Shooting();
    
    return unit;
}

AI_TargetSelector()
{
    self endon("z_death");
    
    while(1) {
        /*if(isDefined(self.activeTarget))
            self.activeTarget sayAll("I am the active target!");*/
        
        wait(4.0 - self.skill);
        
        if(self.isBeingFlashed) // контужен флешкой
            continue;
        
        if(isDefined(self.activeTarget)) {
            dot = vectorDot(vectorNormalize(self.activeTarget.origin - self.origin), vectorNormalize(anglesToForward(self.angles)));
            trace_to_enemy = bulletTrace(self.head getTagOrigin("tag_eye"), self.activeTarget getTagOrigin("j_spine4"), true, self.box);
            
            if(!isDefined(trace_to_enemy["entity"]) || trace_to_enemy["entity"] != self.activeTarget)
                self.activeTarget = undefined;
            
            if(distance2d(self.activeTarget.origin, self.origin) > 5000 + self.skill*2500)
                self.activeTarget = undefined;
            
            if(dot < 0.65 - self.skill*0.15)
                self.activeTarget = undefined;
        }
        
        if(isDefined(self.activeTarget))
            continue;
        
        unconfirmed_targets = [];
        confirmed_targets = [];
        
        // первичная проверка
        foreach(player in level.players) {
            if(!isAlive(player))
                continue;
            
            trace_to_enemy = bulletTrace(self.head getTagOrigin("tag_eye"), player getTagOrigin("j_spine4"), true, self.box);
            
            if(!isDefined(trace_to_enemy["entity"]) || trace_to_enemy["entity"] != player) // игрок не виден?
                continue;
            
            unconfirmed_targets[unconfirmed_targets.size] = player;
        }
        
        // вторичная проверка
        for(i = 0; i < unconfirmed_targets.size; i++) {
            chance = 100 * (self.skill * 1.25);
            dist = distance2d(unconfirmed_targets[i].origin, self.origin);
            dot = vectorDot(vectorNormalize(unconfirmed_targets[i].origin - self.origin), vectorNormalize(anglesToForward(self.angles)));
            max_dist = 5000 + self.skill*2500;
            
            if(dist > max_dist)
                continue;
            
            if(dot < 0.65 - self.skill*0.15)
                continue;
            
            chance = 100 * (self.skill * 1.25);
            
            if(unconfirmed_targets[i] getStance() == "prone")
                chance = chance / 2.2;
            else if(unconfirmed_targets[i] getStance() == "crouch")
                chance = chance / 1.4;
            
            chance = chance / (dist / 1750);
            
            if(dist > 1750 && randomInt(100) > chance)
                continue;
            
            confirmed_targets[confirmed_targets.size] = unconfirmed_targets[i];
        }
        
        //announcement(unconfirmed_targets.size + "," + confirmed_targets.size);
        
        // финальная проверка - выбор приоритетной цели
        if(confirmed_targets.size > 0) {
            self.activeTarget = confirmed_targets[0]; // временно - выбираем самую первую цель
            self notify("z_target", self.activeTarget);
        } else {
            //self.activeTarget = undefined;
        }
    }
}

MasterBot_Logic()
{
    self endon("disconnect");
    
    while(!isDefined(self.pers["team"]))
        wait(0.1);
    
    self notify("menuresponse", game["menu_team"], level.zCfg_Defenders);
    
    wait(0.5);
    
    for(;;) {
        self notify("menuresponse", "changeclass", "class4");
        
        self waittill("spawned_player");
        self setOrigin((798, 5445, 2824));
        self setPlayerAngles((0, 0, 0));
        
        level notify("z_masterbot_spawned", self);
        
        wait(0.1);
    }
}

MasterBot_Spawner()
{
    z_WaittillGameCreated();
    wait(3.5); // не спавним мастер-бота слишком рано
    
    for(;;) {
        level.zMasterBot = addTestClient();
        
        if(isDefined(level.zMasterBot)) {
            level.zMasterBot.pers["master_bot"] = true;
            level.zMasterBot thread MasterBot_Logic();
            
            level.zMasterBot waittill("disconnect");
        }
        
        wait(0.25);
    }
}

SetupAnims()
{
    level.zAI_Anims = [];
    
    level.zAI_Anims["ads_crouch"] = "pb_crouch_ads"; // атакует, встревожен, ищет цель
    level.zAI_Anims["ads_stand"] = "pb_stand_ads"; // атакует, встревожен, ищет цель
    level.zAI_Anims["death_crouch"] = "pb_crouch_death_clutchchest"; // умирает
    level.zAI_Anims["death_stand"] = "pb_stand_death_shoulder_stumble"; // умирает
    level.zAI_Anims["idle_crouch"] = "pb_crouch_alert"; // ничего не делает
    level.zAI_Anims["idle_stand"] = "pb_stand_alert"; // ничего не делает
    level.zAI_Anims["shellshock_crouch"] = "pb_crouch_shellshock"; // ослеплен флешкой
    level.zAI_Anims["shellshock_stand"] = "pb_stand_shellshock"; // ослеплен флешкой
    
    foreach(_anim in level.zAI_Anims)
        precacheMpAnim(_anim);
}

